package com.zhou.common.mybatis.template.oss.util;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.comm.ResponseMessage;
import com.aliyun.oss.model.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.MoreObjects;
import com.zhou.common.base.mq.exception.BizException;
import com.zhou.common.mybatis.template.oss.entity.OssTempFile;
import com.zhou.common.mybatis.template.oss.exception.OssExceptionConstants;
import com.zhou.common.mybatis.template.oss.mapper.OssTempFileMapper;
import com.zhou.common.mybatis.template.oss.model.OssUploadResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.Date;

/**
 * @author zf
 * @since 2020/11/19 11:54 上午
 */
@Component
@Slf4j
public class OssUtil {
    @Value("${oss.endpoint}")
    private String endpoint;

    @Value("${oss.accessKey.id}")
    private String accessKeyId;

    @Value("${oss.accessKey.secret}")
    private String accessKeySecret;

    @Value("${oss.bucket.name}")
    private String bucketName;

    @Value("${oss.dir.name}")
    private String dir;

    @Value("${oss.external.host}")
    private String externalHost;

    @Value("${oss.external.valid-time:1800000}")
    private Long urlValidTime;

    @Value("${oss.internal.host}")
    private String internalHost;

    private OSS ossClient;

    private DateTimeFormatter YEAR_MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyyMM");


    @Autowired
    private ObjectMapper objectMapper;

    @PostConstruct
    public void init() {
        ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        /*if (!ossClient.doesBucketExist(bucketName)) {
            log.info("Bucket {} not exist, creating.", bucketName);
        }*/
        // 不需要检查bucket是否存在，即使不存在，也木有创建的权限 by li.ke
//        if (!ossClient.doesBucketExist(bucketName)) {
//            log.info("Bucket {} not exist, creating.", bucketName);
//            CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
//            createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
//            ossClient.createBucket(createBucketRequest);
//        }
    }

    public OssUploadResult upload(String originalFilename, InputStream is, String dirPath, Long fileSize) throws JsonProcessingException {
        String year_month = YearMonth.now().format(YEAR_MONTH_FORMATTER);
        String day = LocalDate.now().getDayOfMonth() + "";
        String datePart = year_month + "/" + day;
        String targetDir = MoreObjects.firstNonNull(dirPath, dir);

        String suffix = FilenameUtils.getExtension(originalFilename);
        String basename = System.currentTimeMillis() + RandomStringUtils.randomAlphabetic(6).toLowerCase() + "." + suffix;
        String objectKey = targetDir + (targetDir.endsWith("/") ? "" : "/") + datePart + "/" + basename;
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setObjectAcl(CannedAccessControlList.Private);
        PutObjectResult result = ossClient.putObject(bucketName, objectKey, is, metadata);
        ResponseMessage resp = result.getResponse();
        if (resp != null && !resp.isSuccessful()) {
            log.error("upload file failed. {}", objectMapper.writeValueAsString(resp));
            throw new BizException(OssExceptionConstants.UPLOAD_FILE_ERROR);
        }
        OssUploadResult uploadResult = new OssUploadResult();
        uploadResult.setObjectKey(objectKey);
        uploadResult.setObjectUrl(generateUrl(objectKey));
        return uploadResult;
    }

    /**
     * 文件上传V2, 支持自定义业务文件夹
     */

    public String generateUrl(String objectKey) {
        return generateUrl(objectKey, urlValidTime);
    }

    public String generateUrl(String objectKey, Long duration) {
        // 30分钟有效
        Date expiration = new Date(System.currentTimeMillis() + duration);
        URL url = ossClient.generatePresignedUrl(bucketName, objectKey, expiration);
        String internalUrl = url.toString();
        return internalUrl.replace(internalHost, externalHost);
    }


    public OSSObject download(String objKey) {
        GetObjectRequest request = new GetObjectRequest(bucketName, objKey);
        return ossClient.getObject(request);
    }

    @Autowired
    private DefaultMQProducer defaultProducer;

    @Value("${rocketmq.producer.topic}")
    private String ossTopic;

    @Value("${rocketmq.producer.tag}")
    private String ossTag;

    @Autowired
    private OssTempFileMapper ossTempFileMapper;

    @Transactional
    public OssUploadResult upload1(String originalFilename, InputStream is ,String dirPath,Long fileSize) throws JsonProcessingException, InterruptedException, RemotingException, MQClientException, MQBrokerException {
        String year_month = YearMonth.now().format(YEAR_MONTH_FORMATTER);
        String day = LocalDate.now().getDayOfMonth() + "";
        String datePart = year_month + "/" + day;
        String targetDir = MoreObjects.firstNonNull(dirPath, dir);

        String suffix = FilenameUtils.getExtension(originalFilename);
        String basename = System.currentTimeMillis() + RandomStringUtils.randomAlphabetic(6).toLowerCase() + "." + suffix;
        String objectKey = targetDir + (targetDir.endsWith("/") ? "" : "/") + datePart + "/" + basename;
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setObjectAcl(CannedAccessControlList.Private);
        PutObjectResult result = ossClient.putObject(bucketName, objectKey, is, metadata);
        ResponseMessage resp = result.getResponse();
        if (resp != null && !resp.isSuccessful()) {
            log.error("upload file failed. {}", objectMapper.writeValueAsString(resp));
            throw new BizException(OssExceptionConstants.UPLOAD_FILE_ERROR);
        }

        ObjectAcl objectAcl = ossClient.getObjectAcl(bucketName, objectKey);

        ossClient.deleteObject(bucketName,objectKey);

        OssUploadResult uploadResult = new OssUploadResult();
        uploadResult.setObjectKey(objectKey);

        OssTempFile ossTempFile=new OssTempFile();
        ossTempFile.setBucketName(bucketName);
        ossTempFile.setObjectKey(objectKey);
        ossTempFile.setFileSize(fileSize);
        ossTempFileMapper.insert(ossTempFile);
        //延时半个小时发送，测试时暂时用1分钟
        Message message=new Message(ossTopic, ossTag, objectMapper.writeValueAsString(uploadResult).getBytes(StandardCharsets.UTF_8));
        message.setDelayTimeLevel(5);
//        message.setDelayTimeLevel(16);
        defaultProducer.send(message);

        uploadResult.setObjectUrl(generateUrl(objectKey));
        return uploadResult;
    }

    public void deleteObjectKey(String objectKey){
        ossClient.deleteObject(bucketName,objectKey);
    }

}
